package security

import (
	"context"
	"fmt"
	"time"

	"github.com/google/uuid"
	"github.com/sirupsen/logrus"
)

// Role represents a security role
type Role string

const (
	RoleAdmin  Role = "admin"
	RoleUser   Role = "user"
	RoleSystem Role = "system"
	RoleAgent  Role = "agent"
)

// Permission represents a security permission
type Permission string

const (
	PermissionRead   Permission = "read"
	PermissionWrite  Permission = "write"
	PermissionManage Permission = "manage"
	PermissionAdmin  Permission = "admin"
)

// Principal represents an authenticated entity
type Principal struct {
	ID          string
	Name        string
	Roles       []Role
	Permissions []Permission
	Metadata    map[string]interface{}
	CreatedAt   time.Time
	ExpiresAt   time.Time
}

// AuthManager handles authentication and authorization
type AuthManager struct {
	logger     *logrus.Logger
	principals map[string]*Principal
}

// NewAuthManager creates a new auth manager
func NewAuthManager(logger *logrus.Logger) *AuthManager {
	return &AuthManager{
		logger:     logger,
		principals: make(map[string]*Principal),
	}
}

// Authenticate authenticates a principal
func (m *AuthManager) Authenticate(ctx context.Context, name string, credentials map[string]interface{}) (*Principal, error) {
	// TODO: Implement actual authentication logic
	principal := &Principal{
		ID:        uuid.NewString(),
		Name:      name,
		CreatedAt: time.Now(),
		ExpiresAt: time.Now().Add(24 * time.Hour),
		Metadata:  credentials,
	}

	m.principals[principal.ID] = principal
	return principal, nil
}

// Authorize checks if a principal has the required permissions
func (m *AuthManager) Authorize(ctx context.Context, principal *Principal, required []Permission) error {
	if principal == nil {
		return fmt.Errorf("unauthorized: no principal")
	}

	// Admin role has all permissions
	for _, role := range principal.Roles {
		if role == RoleAdmin {
			return nil
		}
	}

	// Check specific permissions
	for _, req := range required {
		found := false
		for _, perm := range principal.Permissions {
			if perm == req {
				found = true
				break
			}
		}
		if !found {
			return fmt.Errorf("unauthorized: missing permission %s", req)
		}
	}

	return nil
}

// GrantRole grants a role to a principal
func (m *AuthManager) GrantRole(ctx context.Context, principal *Principal, role Role) error {
	for _, r := range principal.Roles {
		if r == role {
			return nil
		}
	}
	principal.Roles = append(principal.Roles, role)
	return nil
}

// RevokeRole revokes a role from a principal
func (m *AuthManager) RevokeRole(ctx context.Context, principal *Principal, role Role) error {
	for i, r := range principal.Roles {
		if r == role {
			principal.Roles = append(principal.Roles[:i], principal.Roles[i+1:]...)
			return nil
		}
	}
	return fmt.Errorf("role not found: %s", role)
}

// GrantPermission grants a permission to a principal
func (m *AuthManager) GrantPermission(ctx context.Context, principal *Principal, permission Permission) error {
	for _, p := range principal.Permissions {
		if p == permission {
			return nil
		}
	}
	principal.Permissions = append(principal.Permissions, permission)
	return nil
}

// RevokePermission revokes a permission from a principal
func (m *AuthManager) RevokePermission(ctx context.Context, principal *Principal, permission Permission) error {
	for i, p := range principal.Permissions {
		if p == permission {
			principal.Permissions = append(principal.Permissions[:i], principal.Permissions[i+1:]...)
			return nil
		}
	}
	return fmt.Errorf("permission not found: %s", permission)
}

// Validate validates a principal
func (m *AuthManager) Validate(ctx context.Context, principal *Principal) error {
	if principal == nil {
		return fmt.Errorf("invalid principal: nil")
	}
	if time.Now().After(principal.ExpiresAt) {
		return fmt.Errorf("principal expired")
	}
	return nil
}
